#[cfg(test)]
pub mod test_dref {
    use super::dref;

    #[test]
    fn tdref() {
        dref();
    }
}
pub fn dref() {

    {
        /* 引用(Reference): 关键符 &,  让函数使用某个值 但不获得所有权
            - 这种行为叫借用
            - 引用默认不可变， 不能修改
        */
        println!(" --------- Reference & ------------- ");
        let s = String::from("ref str val");
        let len = ref_calc_str(&s);
        println!("s = {}; len = {}", s, len);
    }

    {
        /* 可变引用 
        */
        println!(" --------- &mut ------------- ");
        let mut s: String = String::from("mut ref str val");
        let len = mut_ref_calc_str(&mut s);
        println!(" s = {}; len = {}", s, len);
        
        let s1 = &mut s;
        println!("s1 = {}", s1);
        /* 限制1: 在特定作用域内, 对某一快数据， 只能有一个可变引用
            - 这样的好处是可在编译时防止数据竞争
            - 以下三种会发生数据竞争
                - 两个或多个指针 同时 访问 同一个数据
                - 至少有一个指针用于写入数据
                - 没有使用任何机制来同步对数据的访问
            - 可以通过创建新的作用域， 来允许 非同时的 创建多个可变引用
         */
        // let s2 = &mut mut_ref_str;
        {
            let s3 = &mut s;
            println!("s3 = {}", s3);
        }

        /* 限制2: 
            - 不可以同时拥有一个可变引用和一个不变引用
            - 多个不变引用是可以的
         */
        let r1 = &s;
        let r2 = &s;
        // let s1 = &mut s;
        println!("r1 = {}", r1);
        println!("r2 = {}", r2);
    }

    {
        /* 悬空引用(Dangling References): 
            - 一个指针指向的内存 已经被释放 且 分配给其他人使用了 
            - 在Rust里， 悬空引用永远不会发生
                如果引用了内容， 编译器保证在引用离开作用域之前 数据不会离开作用域
        */
    }


}


fn ref_calc_str(s: & String) -> usize {
    s.len()
}

fn mut_ref_calc_str(s: &mut String) -> usize {
    s.push_str(" mut_ref_calc_str_push");
    s.len()
}
